<?php

declare(strict_types=1);
/**
 * 创建人 : Forpastime
 *
 * @link     http://hypercmf.com
 * @document https://hyperf.wiki
 * @contact  forpastime@qq.com
 * @git  https://gitee.com/hypercmf/hypercmf1.0.git
 */
namespace App\Middleware\Auth;

use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface as HttpResponse;
use Hyperf\Redis\Redis;
use Hyperf\Utils\ApplicationContext;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class TokenMiddleware implements MiddlewareInterface
{
    /**
     * @var ContainerInterface
     */
    protected $container;

    /**
     * @var HttpResponse
     */
    protected $response;

    /**
     * @var HttpRequest
     */
    protected $request;

    /**
     * TokenMiddleware constructor.
     * @param HttpResponse $response 注意这里的respons 是 ResponseInterface 是hyperf
     * @param RequestInterface $request 注意这里的request 是 RequestInterface  是hyperf
     */
    public function __construct(ContainerInterface $container, HttpResponse $response, RequestInterface $request)
    {
        $this->container = $container;
        $this->request = $request;
        $this->response = $response;
    }

    /**
     * @param ServerRequestInterface $request 注意这个 request 是psr的request 并非 hyperf的
     */
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $authorization = $request->getHeader('Authorization');
        $header = $request->getHeaders();

        if(!set($header['client-type']) || empty($header['client-type'])){
            return $this->response->json(
                [
                    'code' => -1,
                    'data' => [],
                    'msg' => '设备类型异常',
                ]
            );
        }
        if (! empty($authorization)) {
            // 接口鉴权
            $info = explode('_',$authorization);

            //Redis方式
            if(env('AUTH_TYPE',1)==1){
                $redis = ApplicationContext::getContainer()->get(Redis::class);
                if(!$redis->get('HyperCMF:userToken:'.$info[0]) || $redis->get('HyperCMF:userToken:'.$info[0]) != $info[1]){
                    return $this->response->json(
                        [
                            'code' => -1,
                            'data' => [],
                            'msg' => 'Token验证失败！',
                        ]
                    );
                }
            }else{
                //jwt方式 ["alg"=>"HS256","typ"=>"JWT"]
                try {
                    $key = new Key(env("AUTH_SOLT","Hypercmf@2024"),"HS256");
                    $decodeData = JWT::decode($authorization,['hypercmf'=>$key]);
                    if(!$decodeData || !$decodeData->data || $decodeData->data->clientType!=$header['client-type'][0]){
                        return $this->response->json(
                            [
                                'code' => -1,
                                'data' => [],
                                'msg' => 'Token验证失败！',
                            ]
                        );
                    }else{
                        Context::set("userId",$decodeData->data->id);
                    }
                } catch (ExpiredException $e) {
                    return $this->response->json(
                        [
                            'code' => -1,
                            'data' => [],
                            'msg' => 'Token已过期！',
                        ]
                    );
                } catch (SignatureInvalidException $e) {
                    return $this->response->json(
                        [
                            'code' => -1,
                            'data' => [],
                            'msg' => 'Token签名无效！',
                        ]
                    );
                } catch (BeforeValidException $e) {
                    return $this->response->json(
                        [
                            'code' => -1,
                            'data' => [],
                            'msg' => 'Token还未到达有效期！',
                        ]
                    );
                } catch (UnexpectedValueException $e) {
                    return $this->response->json(
                        [
                            'code' => -1,
                            'data' => [],
                            'msg' => 'Token格式不正确！',
                        ]
                    );
                } catch (\Throwable $th) {
                    switch ($th->getMessage()){
                        case "Signature verification failed":
                            $msg = 'Token签名无效！';
                            break;
                        case "Expired token":
                            $msg = 'Token已过期！';
                            break;
                        default:
                            $msg = '发生未知异常！';
                            break;
                    }
                    return $this->response->json(
                        [
                            'code' => -1,
                            'data' => [],
                            'msg' => $msg,
                        ]
                    );
                }
            }
            return $handler->handle($request);
        }else{
            return $this->response->json(
                [
                    'code' => -1,
                    'data' => [],
                    'msg' => 'Token缺失无法验证！',
                ]
            );
        }

    }
}
